/**
 * Created by IntelliJ IDEA.
 * User: Madte
 * Date: 05.07.11
 * Time: 15:21
 * To change this template use File | Settings | File Templates.
 */
if (!ORYX.Plugins) ORYX.Plugins = new Object();
ORYX.Plugins.pmanageMenu = ORYX.Plugins.AbstractPlugin.extend(
{
    facade: undefined,
    construct: function construct(facade)
    {
        this.facade = facade;
        this.facade.offer(
        {
            name: ORYX.I18N.pmanageMenu.btn,
            //add a button to the processwave toolbar
            description: ORYX.I18N.pmanageMenu.btn,
            iconCls: 'pw-toolbar-button pw-toolbar-pmanageMenu-btn',
            functionality: this.beforeshowMenu.bind(this),
            group: ORYX.I18N.pmanageMenu.group,
            isEnabled: function ()
            {
                return true;
            },
            toggle: true,
            index: 1,
            visibleInViewMode: true
        });
        this.json;
        this.privatejson = JSON.parse('[{"text":"Key Success Factors","icon":"../oryx/editor/images/ksf.png","id":"ksf","name":"ksf","attributes":{"name":"ksf"},"allowDrag":false,"expanded":true,"children": []},{"text":"Key Performance Factors","icon":"../oryx/editor/images/kpf.png","id":"kpf","name":"kpf","attributes":{"name":"kpf"},"allowDrag":false,"expanded":true,"children": []},{"text":"Key Performance Indicators","icon":"../oryx/editor/images/kpi.png","id":"kpi","name":"kpi","attributes":{"name":"kpi"},"allowDrag":false,"expanded":true,"children": []}]');
        this.publicjson = JSON.parse('[{"text":"Key Success Factors","icon":"../oryx/editor/images/ksf.png","id":"ksf","name":"ksf","attributes":{"name":"ksf"},"allowDrag":false,"expanded":true,"children": []},{"text":"Key Performance Factors","icon":"../oryx/editor/images/kpf.png","id":"kpf","name":"kpf","attributes":{"name":"kpf"},"allowDrag":false,"expanded":true,"children": []},{"text":"Key Performance Indicators","icon":"../oryx/editor/images/kpi.png","id":"kpi","name":"kpi","attributes":{"name":"kpi"},"allowDrag":false,"expanded":true,"children": []}]');
        this.xhr = new easyXDM.Rpc(
        {
            remote: "http://193.137.47.20:8080/EasyXDM/cors/index.html"
        }, {
            remote: {
                request: {} // request is exposed by /cors/
            }
        });
        this.showCanvas = false;
        console.log("construct this: %o", this);
        this.facade.registerOnEvent(ORYX.CONFIG.EVENT_FARBRAUSCH_NEW_INFOS, this.updateFarbrauschInfos.bind(this));
        this.facade.registerOnEvent(ORYX.CONFIG.EVENT_PMANAGEMENU_SHAPEADD, this.shapeadded.bind(this));
        this.lastcreatedshape;
        // this.init();
    },
    init: function init()
    {},
    shapeadded: function shapeadded(event)
    {
        this.lastcreatedshape = event.shape;
    },
    beforeshowMenu: function beforeshowMenu()
    {
        var that = this;
        this.getTreeData();
        this.loadJSON(that);
        this.showMenu(that);
    },
    showMenu: function showMenu(that) // this function is called when the toolbar button is pressed
    { // constructs/destroys the pmanagemenu
        if (this.pmanageMenu === undefined)
        {
            console.log("showmenu pubicjson: %o /privatejson %o", this.publicjson, this.privatejson);
            this.menuWrapper = document.createElement('div'); // used to position the combobox
            this.menuWrapper.setAttribute('id', 'pwave-pmanageMenu');
            // this.canvasContainer = $$(".ORYX_Editor")[0].parentNode;
            // this.menuWrapper.setAttribute('text-align', 'left');
            document.body.appendChild(this.menuWrapper);
            this.pmanageMenu = new Ext.Panel(
            {
                title: 'Pmanage Menu',
                // the menu with the 3 regions
                id: 'pmanageMenu',
                layout: 'border',
                applyTo: 'pwave-pmanageMenu',
                //autoShow: true,
                height: 300,
                width: 600,
                frame: false,
                header: false,
                handler: {},
                defaults: {
                    frame: false,
                    border: true,
                    split: true,
                    width: 200
                },
                items: [
                {
                    title: 'Canvas',
                    // the tree in the center that represents the canvasshapes
                    region: 'center',
                    id: 'canvastree',
                    xtype: 'treepanel',
                    collapsible: false,
                    //layout: 'fit',
                    animate: true,
                    enableDD: true,
                    dropConfig: {
                        appendOnly: true
                    },
                    autoScroll: true,
                    loader: new Ext.tree.TreeLoader(),
                    // Note: no dataurl, register a TreeLoader to make use of createNode()
                    lines: false,
                    root: new Ext.tree.AsyncTreeNode( //define root node
                    {
                        expanded: true,
                        leaf: false,
                        text: 'Canvas',
                        draggable: false,
                        id: 'source',
                        children: this.json
                    }),
                    rootVisible: true,
                    listeners: { //callbacks for tree functionality
                        click: this.nodeClicked.bind(this),
                        nodedrop: this.addShape.bind(this),
                        beforenodedrop: this.checkDrop.bind(this)
                    }
                }, {
                    title: 'Shapestore',
                    // west region contains shapestore trees
                    region: 'west',
                    xtype: 'tabpanel',
                    id: 'tabpanel',
                    header: true,
                    //width: 200,
                    //minSize: 100,
                    //maxSize: 200,
                    defaults: {
                        // layout: 'fit'
                    },
                    activeTab: 0,
                    tabPosition: 'bottom',
                    listeners: {
                        //  beforerender: this.loadJSON.bind(this)
                    },
                    items: [
                    {
                        title: 'private',
                        // the private per user tree
                        id: 'privatetree',
                        xtype: 'treepanel',
                        collapsible: false,
                        layout: 'fit',
                        animate: true,
                        enableDD: true,
                        hideMode: 'offsets',
                        dropConfig: {
                            appendOnly: true
                        },
                        autoScroll: true,
                        bbar: [
                        {
                            text: 'Save Tree',
                            handler: this.sendJSON.bind(this)
                        }, {
                            text: 'Delete Node',
                            handler: this.delNodeprivate.bind(this)
                        }],
                        loader: new Ext.tree.TreeLoader(),
                        // Note: no dataurl, register a TreeLoader to make use of createNode()
                        lines: false,
                        root: new Ext.tree.AsyncTreeNode(
                        {
                            expanded: false,
                            leaf: false,
                            text: 'Elements',
                            draggable: false,
                            id: 'elements',
                            children: that.privatejson //   this.json //this.getTreeData()//this.facade.getJSON().getChildShapes().toJSON()
                        }),
                        rootVisible: false,
                        listeners: {
                            click: this.nodeClicked.bind(this),
                            beforenodedrop: this.checkDrop.bind(this)
                        }
                    }, {
                        title: 'public',
                        // the public tree for all users
                        id: 'publictree',
                        xtype: 'treepanel',
                        collapsible: false,
                        layout: 'fit',
                        animate: true,
                        hideMode: 'offsets',
                        enableDD: true,
                        dropConfig: {
                            appendOnly: true
                        },
                        autoScroll: true,
                        loader: new Ext.tree.TreeLoader(),
                        // Note: no dataurl, register a TreeLoader to make use of createNode()
                        lines: false,
                        root: new Ext.tree.AsyncTreeNode(
                        {
                            expanded: false,
                            leaf: false,
                            text: 'Canvas',
                            draggable: false,
                            id: 'source',
                            children: that.publicjson
                        }),
                        rootVisible: false,
                        listeners: {
                            click: this.nodeClicked.bind(this),
                            beforenodedrop: this.checkDrop.bind(this)
                        }
                    }]
                }, {
                    title: 'Properties',
                    // the properties grid on the east region
                    region: 'east',
                    id: 'grid',
                    xtype: 'grid',
                    layout: 'fit',
                    //..other config here
                    store: new Ext.data.SimpleStore( //define the store
                    {
                        fields: ['Property', 'Value'],
                        reader: new Ext.data.ArrayReader()
                    }),
                    view: new Ext.grid.GridView( //define the gridview
                    {
                        autoFill: true,
                        forceFit: false
                    }),
                    cm: new Ext.grid.ColumnModel( // define the columnModel
                    {
                        columns: [
                        {
                            id: 'property',
                            header: 'Property',
                            DataIndex: 'Property'
                        }, {
                            id: 'value',
                            header: 'Value',
                            DataIndex: 'Value'
                        }]
                    })
                    //width: 200,
                    //height: 240
                    //minSize: 100,
                    //maxSize: 200
                }]
            });
            this.pmanageMenu.hide();
        }
        if (this.pmanageMenu.isVisible() === true) // in this case the menu is currently displayed
        {
            this.pmanageMenu.hide();
            this.pmanageMenu.destroy(); // hide and delete it
            delete this.pmanageMenu;
        }
        else // menu is not currently displayed
        {
            this.pmanageMenu.findById('privatetree').getRootNode().reload();
            this.pmanageMenu.show();
            this.pmanageMenu.doLayout();
            this.pmanageMenu.render();
        }
    },
    updateFarbrauschInfos: function updateFarbrauschInfos(evt)
    {
        this.users = evt.users;
        console.log("this.users: %o", this.users);
    },
    sendJSON: function sendJSON()
    {
        var win = window.open("");
        win.document.open();
        win.document.write("<p>Exporting...</p>");
        // write something so the HTML body is present.
        win.document.close();
        var submitForm = win.document.createElement("form");
        win.document.body.appendChild(submitForm);
        var createHiddenElement = function (name, value)
            {
                var newElement = document.createElement("input");
                newElement.name = name;
                newElement.type = "hidden";
                newElement.value = value;
                return newElement;
            }
        submitForm.appendChild(createHiddenElement("tree", this.treeToJson()));
        submitForm.appendChild(createHiddenElement("user", this.users[this.facade.getUserId()].displayName));
        submitForm.appendChild(createHiddenElement("action", "save"));
        submitForm.method = "POST";
        submitForm.action = "http://193.137.47.20:8080/Shapestore_war_exploded/shapestore";
        submitForm.submit();
/*  var socket = new easyXDM.Socket({
            remote: "http://193.137.47.20:8080/Shapestore_war_exploded/shapestore", // the path to the provider
            onMessage:function(message, origin) {
                console.log("message: %o", message);//do something with message
                console.log("origin: %o", origin);
            }
          });

       socket.postMessage('tree=[{"id": 1,"text": "AleafNode","leaf": true},{"id": 2,"text": "AfolderNode","children": [{"id": 3,"text": "AchildNode","leaf": true}]}]');
          */
    },
    loadJSON: function loadJSON(that)
    {
        //   console.log("component: %o", Extcomponent);
        //  var tree = this.pmanageMenu.findById('publictree');
        console.log("loadjson this: %o", this);
        // var that = this;
        this.xhr.request(
        {
            url: "http://193.137.47.20:8080/Shapestore_war_exploded/shapestore/savedTrees/" + this.users[this.facade.getUserId()].displayName + "/privatetree.json",
            method: "GET"
        }, function (response)
        {
            status = response.status;
            //alert(response.data);
            console.log("status: %o", status);
            console.log("data: %o", response.data);
            if (status === 200)
            { //get successful
                that.privatejson = JSON.parse(response.data);
                console.log("privatejson: %o", that.privatejson);
            }
        });
        this.xhr.request(
        {
            url: "http://193.137.47.20:8080/Shapestore_war_exploded/shapestore/savedTrees/public/privatetree.json",
            method: "GET"
        }, function (response)
        {
            status = response.status;
            //alert(response.data);
            console.log("status: %o", status);
            console.log("data: %o", response.data);
            if (status === 200)
            { //get successful
                that.publicjson = JSON.parse(response.data);
                console.log("publicjson: %o", that.publicjson);
            }
        });

    },
    getTreeData: function getTreeData() // this function creates data for the canvastree out of the canvasshapes
    {
        function isEmpty(obj)
        {
            for (var prop in obj)
            {
                if (obj.hasOwnProperty(prop)) return false;
            }
            return true;
        }
        var shapes = (this.facade.getJSON()).childShapes; // get all parent shapes from the canvas (ksf,kpf,stakeholder)
        var jsonForTree = new Array;
        var entry = new Object;
        console.log("json: %o", shapes);
        for (var i = 0; i < shapes.length; i++) // create a treenode for each shape including kpis
        {
            console.log("childshape %o, (%o)", shapes[i], i);
            // only regard the possible shapetypes
            if (shapes[i].stencil.id === "stakeholder" || shapes[i].stencil.id === "ksf" || shapes[i].stencil.id === "kpf")
            {
                entry = {};
                entry.id = shapes[i].properties.name;
                entry.text = shapes[i].properties.name;
                entry.attributes = {};
                entry.attributes = shapes[i].properties;
                if (isEmpty(shapes[i].childShapes))
                { // shape has no kpis
                    entry.icon = '../oryx/editor/images/' + shapes[i].stencil.id + '.png';
                    entry.children = [];
                    entry.expanded = true;
                    entry.allowDrop = true;
                    entry.allowChildren = true;
                    entry.attributes['type'] = shapes[i].stencil.id;
                    entry.attributes['cid'] = shapes[i].resourceId;
                    jsonForTree.push(entry);
                }
                else
                { //shape has kpis
                    entry.leaf = false;
                    entry.icon = '../oryx/editor/images/' + shapes[i].stencil.id + '.png';
                    entry.attributes['type'] = shapes[i].stencil.id;
                    entry.attributes['cid'] = shapes[i].resourceId;
                    entry.children = new Array;
                    for (var j = 0; j < shapes[i].childShapes.length; j++)
                    { //create kpi nodes
                        entry.children[j] = {};
                        entry.children[j].id = shapes[i].properties.name + "/" + shapes[i].childShapes[j].properties.name;
                        entry.children[j].text = shapes[i].childShapes[j].properties.name;
                        entry.children[j].attributes = {};
                        entry.children[j].attributes = shapes[i].childShapes[j].properties;
                        entry.children[j].attributes['type'] = shapes[i].childShapes[j].stencil.id;
                        entry.children[j].attributes['cid'] = shapes[i].childShapes[j].resourceId;
                        entry.children[j].icon = '../oryx/editor/images/kpi.png';
                        entry.children[j].leaf = true;
                    }
                    jsonForTree.push(entry);
                }
            }
        }
        this.json = jsonForTree;
        console.log("this json %o", this.json);
        console.log("this json %o", this.json.toJSON());
    },
    addShape: function addShape(dropEvent) // this function creates shapes on the canvas for dropevents on the canvastree
    {
        function isEmpty(obj)
        {
            for (var prop in obj)
            {
                if (obj.hasOwnProperty(prop)) return false;
            }
            return true;
        }
        console.log("dropevent", dropEvent);
        var shape = dropEvent.dropNode.attributes.attributes; // the shape that is dropped
        //Create parent node
        /**
         *   option = {
         *       type: string,
         *       position: {x:int, y:int},
         *       connectingType:     uiObj-Class
         *       connectedShape: uiObj
         *       draggin: bool
         *       namespace: url
         *       parent: ORYX.Core.AbstractShape
         *       template: a template shape that the newly created inherits properties from.
         *       }
         */
        var shapetype = "http://b3mn.org/stencilset/pmanage#" + shape.type; // the shapetype with namespace
        if (shapetype === "http://b3mn.org/stencilset/pmanage#kpi") // shape is a kpi
        {
            var parent = this.facade.getCanvas().getChildShapeByResourceId(dropEvent.target.attributes.attributes.cid); // find parentshape by oryx id
            var option = {
                type: shapetype,
                position: { // position where the shape appears
                    x: 10,
                    y: 100
                },
                namespace: "http://b3mn.org/stencilset/pmanage#",
                parent: parent
            };
        }
        else // shape is stakeholder,ksf,kpf
        {
            if (!isEmpty(dropEvent.dropNode.attributes.children)) var childs = dropEvent.dropNode.attributes.children.toArray(); // if the shape contains kpis save them for later
            var option = {
                type: shapetype,
                position: {
                    x: 10,
                    y: 100
                },
                namespace: "http://b3mn.org/stencilset/pmanage#",
                parent: this.facade.getCanvas() // parent is always the canvas
            };
        }
        var command = new ORYX.Core.Commands["ShapeRepository.DropCommand"](option, option.parent, true, option.position, this.facade);
        this.facade.executeCommands([command]);
        var createdshape = [];
        createdshape[0] = this.lastcreatedshape;
        console.log("createdshape: %o", createdshape);
        for (var prop in shape) // copy the attributes from the treenode to the new shape
        {
            if (shape.hasOwnProperty(prop))
            {
                if (prop !== "type" && prop !== "cid")
                {
                    command = new ORYX.Core.Commands["PropertyChange"]("oryx-" + prop, createdshape, "", shape[prop], this.facade);
                    this.facade.executeCommands([command]);
                }
            }
        }
        //create child shapes
        if (!isEmpty(childs) && (shapetype !== "kpi")) // shape has childs and is not a kpi
        {
            console.log("childs: %o", childs);
            for (var i = 0; i < childs.length; i++) // create all kpis of the shape
            {
                var opt = {
                    type: "http://b3mn.org/stencilset/pmanage#kpi",
                    position: {
                        x: 0,
                        y: 0
                    },
                    namespace: "http://b3mn.org/stencilset/pmanage#",
                    parent: createdshape[0] // parent is the above created shape
                };
                var command = new ORYX.Core.Commands["ShapeRepository.DropCommand"](opt, opt.parent, true, opt.position, this.facade);
                this.facade.executeCommands([command]);
                var childshape = [];
                childshape[0] = this.lastcreatedshape;
                for (var prop in childs[i].attributes) // copy data from treenode to kpi
                {
                    if (childs[i].attributes.hasOwnProperty(prop))
                    {
                        console.log("property: %o", prop);
                        if (prop !== "type" && prop !== "cid")
                        {
                            command = new ORYX.Core.Commands["PropertyChange"]("oryx-" + prop, childshape, "", childs[i].attributes[prop], this.facade);
                            this.facade.executeCommands([command]);
                        }
                    }
                }
            }
        }
        this.facade.getCanvas().update(); // update the canvas
    },
    delNodeprivate: function delNodeprivate() // function for deleting treenodes in privatetree
    {
        var tree = this.pmanageMenu.findById('privatetree'); // get privatetree
        var selectionModel = tree.getSelectionModel();
        var selectedNode = selectionModel.getSelectedNode(); // get selected node
        if (selectedNode === null) return; // do nothing if there is no node selected
        if (selectedNode.id !== 'ksf' && selectedNode.id !== 'kpf' && selectedNode.id !== 'kpi')
        { // dont allow deletion of rootnodes
            selectedNode.remove();
        }
    },
    checkDrop: function checkDrop(dropEvent) // this function handles the drag and drop between canvastree and shapestore
    {
        dropEvent.dropNode.expand(); // expand node before drop in order to also copy the childnodes
        var treepanel = this.pmanageMenu.findById(dropEvent.tree.id); // get the treepanel where the node was dragged

        function copyDropNode(node, dropEvent) // small helper function that allows us to copy nodes and not just cut
        {
            var newNode = new Ext.tree.TreeNode(Ext.apply(
            {}, node.attributes));
            if (dropEvent.dropNode.attributes.attributes.type === "kpi") // if it´s a kpi generate a unique treenode id
            { //new id of kpi will be it´s parents name + the own (e.g. KPF2/KPI1)
                var newid = dropEvent.target.attributes.attributes.name + "/" + dropEvent.dropNode.attributes.attributes.name;
                newNode.id = newid;
            }
            for (var i = 0; i < node.childNodes.length; i++)
            {
                n = node.childNodes[i];
                if (n)
                {
                    newNode.appendChild(copyDropNode(n, dropEvent)); //call the function recursive for all childnodes
                }
            }
            return newNode;
        }
        if (dropEvent.tree.id === "privatetree" || dropEvent.tree.id === "publictree")
        { // handle drop on shapestore trees
            if (dropEvent.dropNode.attributes.attributes.type === "kpf" && dropEvent.target.id !== "kpf") return false; /*only allow drops on the correct category*/
            if (dropEvent.dropNode.attributes.attributes.type === "ksf" && dropEvent.target.id !== "ksf") return false; /*only allow drops on the correct category*/
            if (dropEvent.dropNode.attributes.attributes.type === "stakeholder") return false; // stakeholder not allowed in shapestore
            if (dropEvent.target.id === "kpi")
            { //drop on the Key Performance Indicators Node
                if (dropEvent.dropNode.attributes.attributes.type !== "kpi") return false; //dropnode is not kpi
            }
        }
        else
        {
            if (dropEvent.dropNode.attributes.attributes.type === "kpi" && dropEvent.target.attributes.id === "source") return false; // don´t allow drag kpi on canvas
            if (dropEvent.dropNode.attributes.attributes.type === "kpi" && dropEvent.target.attributes.attributes.type === "stakeholder") return false; // don´t allow kpi on stakeholder
            if (dropEvent.dropNode.attributes.attributes.type !== "kpi" && dropEvent.target.attributes.id !== "source") return false; // only allow other shapes than kpi to append on root
        }
        console.log("node: %o", dropEvent);
        if (dropEvent.dropNode.attributes.attributes.type !== 'kpi') // dropped node is not a kpi
        { // only allow double nodes when it´s kpi
            console.log("treepanel: %o", treepanel);
            var samenode = treepanel.getNodeById(dropEvent.dropNode.attributes.id); // shape only allowed once per subtree
            console.log("node: %o", samenode);
            if (samenode !== undefined) return false;
            //make a copy of the node that is dropped
            var n = dropEvent.dropNode; // the node that was dropped
            dropEvent.dropNode = copyDropNode(n, dropEvent); // assign the copy as the new dropNode so we keep the dropped node in the tree
            return true;
        }
        if (dropEvent.dropNode.attributes.attributes.type === 'kpi') // dropped node is a kpi
        { //generate new id for a by copy newly created kpi
            var samenode = treepanel.getNodeById(dropEvent.target.attributes.attributes.name + "/" + dropEvent.dropNode.attributes.attributes.name); // no double kpis allowed under this node
            if (samenode !== undefined) return false;
            //make a copy of the node that is dropped
            var Node = dropEvent.dropNode;
            dropEvent.dropNode = copyDropNode(Node, dropEvent);
            return true; //allow drop
        }
    },
    nodeClicked: function nodeClicked(node, event) // this function display the clicked nodes properties in the propertygrid
    {
        console.log("node: %o", node);
        var attributeArray = [];
        var vals = [];
        // Get the properties and values from the nodes attributes object into arrays for the grid
        for (var propertyName in node.attributes.attributes)
        {
            var temp = [propertyName, node.attributes.attributes[propertyName]];
            attributeArray.push(temp);
        }
        var grid = this.pmanageMenu.findById('grid'); // get the propertygrid
        grid.getStore().loadData(attributeArray); // load the grids store with the attribute array
        grid.render(); // render the grid
        grid.doLayout();
        this.pmanageMenu.doLayout(); // call the layout function of the pmanagemenu
    },
    treeToJson: function treeToJson(button, eventObject) // this function generates a json string out of a extjs tree
    {
         var tree = this.pmanageMenu.findById('privatetree'); // get privatetree
        tree.expandAll()

        function getNodeList(bfsQueue)
        {
            var node = bfsQueue.pop();
            var nodeQueue = [];
            for (var ii = 0; ii < node.childNodes.length; ii++)
            {
                bfsQueue.push(node.childNodes[ii]);
                nodeQueue.push(node.childNodes[ii]);
            }
              if (bfsQueue.length === 0)
            {
                return nodeQueue;
            }
            else
            {
                return nodeQueue.concat(getNodeList(bfsQueue));
            }
        }
        var startQueue = [];
        var nodeList = [];
        startQueue.push(tree.getRootNode());
        nodeList.push(tree.getRootNode());
        nodeList = nodeList.concat(getNodeList(startQueue));
        nodeList.shift(); // remove root node
        console.dir(nodeList);
        for (var nn = nodeList.length - 1; nn >= 0; nn--)
        {
            var params = [];
            for (var pp in nodeList[nn].attributes)
            {
                if (pp === "children" || pp === "loader")
                {
                    continue;
                }
                params.push('"' + pp + '":' + JSON.stringify(nodeList[nn].attributes[pp]) + '');
            }
            if (nodeList[nn].childNodes.length > 0)
            {
                var childList = [];
                for (var ii = 0; ii < nodeList[nn].childNodes.length; ii++)
                {
                    childList.push(nodeList[nn].childNodes[ii].json);
                }
                params.push('"children": [' + childList.join(',') + ']');
            }
            else
            {
                params.push('"children": []');
            }
            nodeList[nn].json = "{" + params.join(",") + "}";
        }
        var json = "[";
        for (var nnn = 0; nnn <= 2; nnn++)
        {
            if (nnn !== 2)
            {
                json += (nodeList[nnn].json + ",");
            }
            else
            {
                json += nodeList[nnn].json;
            }
        }
        json += "]";

        tree.collapseAll();
        return json; //"[" + nodeList[0].json + "]";
    }
});